<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>视频转WebP动态图工具</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/ffmpeg/0.11.6/ffmpeg.min.js"></script>
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        font-family: 'SF Pro Display', 'PingFang SC', 'Helvetica Neue', Arial,
          sans-serif;
      }

      :root {
        --primary-bg: #e6e7ee;
        --secondary-bg: #ffffff;
        --shadow-light: #ffffff;
        --shadow-dark: #d1d9e6;
        --accent-color: #667eea;
        --accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        --success-color: #4ecdc4;
        --danger-color: #ff6b6b;
        --warning-color: #feca57;
        --text-primary: #2d3748;
        --text-secondary: #718096;
        --glass-bg: rgba(255, 255, 255, 0.25);
        --glass-border: rgba(255, 255, 255, 0.18);
      }

      body {
        background: var(--primary-bg);
        color: var(--text-primary);
        min-height: 100vh;
        padding: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        transition: all 0.3s ease;
        animation: pageLoad 0.8s ease;
      }

      @keyframes pageLoad {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .container {
        width: 100%;
        max-width: 1200px;
        background: var(--primary-bg);
        border-radius: 30px;
        padding: 40px;
        box-shadow: 20px 20px 60px var(--shadow-dark),
          -20px -20px 60px var(--shadow-light);
        margin-top: 20px;
        transition: all 0.3s ease;
        animation: containerFloat 1s ease 0.2s both;
      }

      @keyframes containerFloat {
        from {
          opacity: 0;
          transform: translateY(30px) scale(0.95);
        }
        to {
          opacity: 1;
          transform: translateY(0) scale(1);
        }
      }

      .container:hover {
        box-shadow: 25px 25px 70px var(--shadow-dark),
          -25px -25px 70px var(--shadow-light);
      }

      header {
        text-align: center;
        margin-bottom: 40px;
        padding: 30px;
        background: var(--primary-bg);
        border-radius: 25px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: headerSlide 0.8s ease 0.4s both;
      }

      @keyframes headerSlide {
        from {
          opacity: 0;
          transform: translateY(-30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      h1 {
        font-size: 3.2rem;
        margin-bottom: 15px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        font-weight: 700;
        animation: titleGlow 3s ease-in-out infinite alternate;
      }

      @keyframes titleGlow {
        from {
          filter: brightness(1);
        }
        to {
          filter: brightness(1.2);
        }
      }

      .subtitle {
        font-size: 1.3rem;
        color: var(--text-secondary);
        margin-bottom: 30px;
        font-weight: 500;
      }

      .panels {
        display: flex;
        gap: 30px;
        margin-bottom: 40px;
        animation: panelsSlide 0.8s ease 0.6s both;
      }

      @keyframes panelsSlide {
        from {
          opacity: 0;
          transform: translateX(-20px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      .panel {
        flex: 1;
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        transition: all 0.3s ease;
        position: relative;
        overflow: hidden;
      }

      .panel::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.1),
          transparent
        );
        transition: left 0.8s;
      }

      .panel:hover::before {
        left: 100%;
      }

      .panel:hover {
        transform: translateY(-5px);
        box-shadow: 16px 16px 32px var(--shadow-dark),
          -16px -16px 32px var(--shadow-light);
      }

      .panel-title {
        font-size: 1.6rem;
        margin-bottom: 25px;
        color: var(--accent-color);
        display: flex;
        align-items: center;
        font-weight: 600;
      }

      .panel-title::before {
        content: attr(data-icon);
        margin-right: 12px;
        font-size: 1.8rem;
        animation: iconBounce 2s ease-in-out infinite;
      }

      @keyframes iconBounce {
        0%,
        100% {
          transform: scale(1);
        }
        50% {
          transform: scale(1.1);
        }
      }

      .file-upload {
        border: 3px dashed var(--accent-color);
        border-radius: 25px;
        padding: 50px 40px;
        text-align: center;
        transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
        margin-bottom: 25px;
        cursor: pointer;
        background: var(--primary-bg);
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      .file-upload:hover {
        border-color: var(--success-color);
        transform: translateY(-5px) scale(1.02);
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light),
          0 15px 40px rgba(102, 126, 234, 0.25), 0 5px 15px rgba(0, 0, 0, 0.1);
      }

      .file-upload.dragover {
        border-color: var(--success-color);
        background: rgba(78, 205, 196, 0.05);
        transform: scale(1.05);
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light),
          0 20px 50px rgba(78, 205, 196, 0.3);
        animation: dragPulse 1s ease-in-out infinite;
      }

      @keyframes dragPulse {
        0%,
        100% {
          border-color: var(--success-color);
        }
        50% {
          border-color: var(--accent-color);
        }
      }

      .file-upload-content {
        position: relative;
        z-index: 1;
      }

      .file-upload-icon {
        font-size: 3.5rem;
        margin-bottom: 20px;
        display: block;
        animation: iconFloat 3s ease-in-out infinite;
        filter: drop-shadow(0 4px 8px rgba(102, 126, 234, 0.2));
      }

      @keyframes iconFloat {
        0%,
        100% {
          transform: translateY(0);
        }
        50% {
          transform: translateY(-10px);
        }
      }

      .file-upload-text {
        font-size: 1.4rem;
        font-weight: 600;
        color: var(--text-primary);
        margin-bottom: 10px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
      }

      .file-upload-subtext {
        font-size: 1.1rem;
        color: var(--text-secondary);
        margin-bottom: 20px;
        font-weight: 500;
      }

      .file-upload-formats {
        font-size: 0.9rem;
        color: var(--accent-color);
        font-weight: 500;
        padding: 8px 16px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 20px;
        display: inline-block;
        margin-bottom: 20px;
      }

      .file-upload input[type='file'] {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        opacity: 0;
        cursor: pointer;
        z-index: 2;
      }

      .video-preview {
        width: 100%;
        background: var(--primary-bg);
        border-radius: 20px;
        overflow: hidden;
        margin-top: 20px;
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light);
        transition: all 0.3s ease;
        display: none;
      }

      .video-preview:hover {
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light);
      }

      video {
        width: 100%;
        max-height: 300px;
        display: block;
        border-radius: 15px;
      }

      .options-form {
        display: flex;
        gap: 20px;
        margin-bottom: 25px;
        flex-wrap: wrap;
        align-items: flex-end;
      }

      .form-group {
        flex: 1;
        min-width: 150px;
      }

      label {
        display: block;
        margin-bottom: 10px;
        color: var(--text-secondary);
        font-weight: 500;
        font-size: 0.95rem;
      }

      input,
      select {
        width: 100%;
        padding: 14px 18px;
        background: var(--primary-bg);
        border: none;
        border-radius: 15px;
        color: var(--text-primary);
        font-size: 1rem;
        font-weight: 500;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        transition: all 0.3s ease;
      }

      input:focus,
      select:focus {
        outline: none;
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light),
          0 0 0 3px rgba(102, 126, 234, 0.2);
      }

      button {
        background: var(--primary-bg);
        color: var(--text-primary);
        border: none;
        padding: 14px 28px;
        border-radius: 15px;
        cursor: pointer;
        font-weight: 600;
        transition: all 0.3s ease;
        font-size: 1rem;
        flex-shrink: 0;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      button::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.2),
          transparent
        );
        transition: left 0.5s;
      }

      button:hover::before {
        left: 100%;
      }

      button:hover {
        transform: translateY(-3px);
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
      }

      button:active {
        transform: translateY(0);
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
      }

      button:disabled {
        opacity: 0.6;
        cursor: not-allowed;
        transform: none;
        box-shadow: 4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
      }

      .btn-primary {
        background: var(--accent-gradient);
        color: white;
        padding: 16px 32px;
        font-size: 1.1rem;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .btn-primary:hover {
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2),
          0 0 30px rgba(102, 126, 234, 0.3);
      }

      .btn-success {
        background: linear-gradient(
          135deg,
          var(--success-color) 0%,
          #44a08d 100%
        );
        color: white;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .progress-container {
        margin: 30px 0;
        animation: progressSlide 0.8s ease 0.8s both;
        display: none;
      }

      @keyframes progressSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .progress-bar {
        height: 16px;
        background: var(--primary-bg);
        border-radius: 20px;
        overflow: hidden;
        margin-bottom: 15px;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        position: relative;
      }

      .progress-fill {
        height: 100%;
        background: var(--accent-gradient);
        width: 0%;
        transition: width 0.3s ease;
        border-radius: 20px;
        box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3);
        position: relative;
        overflow: hidden;
      }

      .progress-fill::after {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.3),
          transparent
        );
        animation: progressShine 2s infinite;
      }

      @keyframes progressShine {
        0% {
          left: -100%;
        }
        100% {
          left: 100%;
        }
      }

      .progress-text {
        text-align: center;
        font-size: 1rem;
        color: var(--text-secondary);
        font-weight: 500;
      }

      .actions {
        display: flex;
        justify-content: center;
        gap: 25px;
        margin-top: 30px;
        animation: actionsSlide 0.8s ease 1s both;
      }

      @keyframes actionsSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .result-panel {
        text-align: center;
        animation: resultPanelSlide 0.8s ease 1.2s both;
      }

      @keyframes resultPanelSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .status-message {
        min-height: 35px;
        margin: 20px 0;
        color: var(--accent-color);
        font-weight: 600;
        font-size: 1.1rem;
        transition: all 0.3s ease;
      }

      .status-message.processing {
        animation: statusPulse 1.5s ease-in-out infinite;
      }

      @keyframes statusPulse {
        0%,
        100% {
          opacity: 1;
        }
        50% {
          opacity: 0.6;
        }
      }

      .error-message {
        color: var(--danger-color);
        margin: 20px 0;
        min-height: 35px;
        font-weight: 600;
        font-size: 1.1rem;
        animation: errorShake 0.5s ease;
      }

      @keyframes errorShake {
        0%,
        100% {
          transform: translateX(0);
        }
        25% {
          transform: translateX(-5px);
        }
        75% {
          transform: translateX(5px);
        }
      }

      .download-section {
        display: none;
        flex-direction: column;
        gap: 20px;
        margin-top: 30px;
        padding: 25px;
        background: var(--primary-bg);
        border-radius: 25px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        border: 2px solid var(--accent-color);
      }

      .webp-preview {
        text-align: center;
        margin-bottom: 20px;
      }

      .webp-preview img {
        max-width: 100%;
        max-height: 400px;
        border-radius: 15px;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
      }

      .webp-info {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20px;
        padding: 15px;
        background: var(--primary-bg);
        border-radius: 15px;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
      }

      .webp-info-item {
        text-align: center;
      }

      .webp-info-label {
        font-size: 0.9rem;
        color: var(--text-secondary);
        margin-bottom: 5px;
      }

      .webp-info-value {
        font-size: 1.1rem;
        font-weight: 600;
        color: var(--text-primary);
      }

      .instructions {
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        margin-top: 40px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: instructionsSlide 0.8s ease 1.4s both;
      }

      @keyframes instructionsSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .instructions h3 {
        color: var(--accent-color);
        margin-bottom: 20px;
        font-size: 1.4rem;
        font-weight: 600;
      }

      .instructions ol {
        padding-left: 25px;
        margin-bottom: 20px;
      }

      .instructions li {
        margin-bottom: 12px;
        line-height: 1.7;
        color: var(--text-secondary);
        font-weight: 500;
      }

      .instructions p {
        color: var(--text-secondary);
        font-style: italic;
        font-weight: 500;
        padding: 15px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 15px;
        border-left: 4px solid var(--accent-color);
      }

      footer {
        margin-top: 40px;
        text-align: center;
        color: var(--text-secondary);
        font-size: 0.95rem;
        padding: 25px;
        background: var(--primary-bg);
        border-radius: 20px;
        box-shadow: 6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
        animation: footerFade 0.8s ease 1.6s both;
      }

      @keyframes footerFade {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }

      .time-controls {
        display: flex;
        gap: 15px;
        align-items: center;
        margin-bottom: 20px;
        flex-wrap: wrap;
      }

      .time-display {
        font-size: 1rem;
        font-weight: 600;
        color: var(--accent-color);
        padding: 8px 16px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 15px;
        border: 1px solid rgba(102, 126, 234, 0.2);
      }

      .checkbox-group {
        display: flex;
        align-items: center;
        gap: 15px;
        margin-bottom: 25px;
        padding: 20px;
        background: var(--primary-bg);
        border-radius: 15px;
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        border: 2px solid var(--accent-color);
        transition: all 0.3s ease;
      }

      .checkbox-group:hover {
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light);
        border-color: var(--success-color);
      }

      .checkbox-group input[type='checkbox'] {
        width: 20px;
        height: 20px;
        margin: 0;
        accent-color: var(--accent-color);
        cursor: pointer;
      }

      .checkbox-group label {
        margin: 0;
        cursor: pointer;
        font-size: 1.1rem;
        font-weight: 600;
        color: var(--text-primary);
        display: flex;
        align-items: center;
        gap: 8px;
      }

      .checkbox-group label::before {
        content: '⏱️';
        font-size: 1.2rem;
      }

      .video-limit-notice {
        background: rgba(255, 193, 7, 0.1);
        border: 2px solid var(--warning-color);
        border-radius: 15px;
        padding: 20px;
        margin: 20px 0;
        color: var(--text-primary);
        font-size: 0.95rem;
        line-height: 1.6;
      }

      .video-limit-notice h4 {
        color: var(--warning-color);
        margin-bottom: 10px;
        font-size: 1.1rem;
        font-weight: 600;
        display: flex;
        align-items: center;
        gap: 8px;
      }

      .video-limit-notice h4::before {
        content: '⚠️';
        font-size: 1.2rem;
      }

      .video-limit-notice a {
        color: var(--accent-color);
        text-decoration: none;
        font-weight: 600;
        border-bottom: 1px solid transparent;
        transition: all 0.3s ease;
      }

      .video-limit-notice a:hover {
        border-bottom-color: var(--accent-color);
        color: var(--success-color);
      }
    </style>
  </head>
  <body>
    <div class="container">
      <header>
        <h1>🎬 视频转WebP动态图</h1>
        <p class="subtitle">
          将视频转换为高质量的WebP动态图片，支持自定义时长和质量设置
        </p>
      </header>

      <div class="panels">
        <!-- 视频上传面板 -->
        <div class="panel">
          <div class="panel-title" data-icon="📁">视频上传</div>

          <div class="file-upload" id="fileUpload">
            <div class="file-upload-content">
              <span class="file-upload-icon">🎥</span>
              <div class="file-upload-text">点击或拖拽上传视频</div>
              <div class="file-upload-subtext">支持多种视频格式</div>
              <div class="file-upload-formats">MP4, AVI, MOV, MKV, WEBM</div>
            </div>
            <input type="file" id="videoInput" accept="video/*" />
          </div>

          <div class="video-preview" id="videoPreview">
            <!-- 视频预览将在这里显示 -->
          </div>
        </div>

        <!-- 转换设置面板 -->
        <div class="panel">
          <div class="panel-title" data-icon="⚙️">转换设置</div>

          <div class="video-limit-notice">
            <h4>浏览器限制说明</h4>
            <p>
              由于浏览器性能限制，本工具默认只支持1080p及以下分辨率的视频转换。如果您的视频分辨率大于1080p，请先访问
              <a
                href="https://www.996day.com/video-compress.html"
                target="_blank"
                >视频压缩工具</a
              >
              进行压缩处理后再使用本工具。
            </p>
          </div>

          <div class="checkbox-group">
            <input type="checkbox" id="useFullDuration" checked />
            <label for="useFullDuration">使用完整视频时长</label>
          </div>

          <div class="options-form" id="timeSettings" style="display: none">
            <div class="form-group">
              <label for="startTime">开始时间 (秒)</label>
              <input
                type="number"
                id="startTime"
                value="0"
                min="0"
                step="0.1"
              />
            </div>
            <div class="form-group">
              <label for="endTime">结束时间 (秒)</label>
              <input
                type="number"
                id="endTime"
                value="10"
                min="0.1"
                step="0.1"
              />
            </div>
          </div>

          <div class="time-controls" id="timeControls" style="display: none">
            <button type="button" onclick="getCurrentTime('start')">
              📍 当前时间为开始
            </button>
            <button type="button" onclick="getCurrentTime('end')">
              📍 当前时间为结束
            </button>
            <div class="time-display" id="currentTimeDisplay">00:00</div>
          </div>

          <div class="options-form">
            <div class="form-group">
              <label for="quality">质量设置</label>
              <select id="quality">
                <option value="high" selected>高质量 (较大文件)</option>
                <option value="medium">中等质量 (推荐)</option>
                <option value="low">低质量 (较小文件)</option>
              </select>
            </div>
            <div class="form-group">
              <label for="fps">帧率 (FPS)</label>
              <select id="fps">
                <option value="10">10 FPS</option>
                <option value="15">15 FPS</option>
                <option value="20">20 FPS</option>
                <option value="24">24 FPS</option>
                <option value="30" selected>30 FPS (推荐)</option>
                <option value="60">60 FPS</option>
                <option value="custom">自定义</option>
              </select>
            </div>
            <div class="form-group" id="customFpsGroup" style="display: none">
              <label for="customFps">自定义帧率</label>
              <input
                type="number"
                id="customFps"
                min="1"
                max="120"
                value="24"
                placeholder="输入帧率 (1-120)"
              />
            </div>
            <div class="form-group">
              <label for="width">宽度 (像素)</label>
              <select id="width">
                <option value="-1" selected>保持原始</option>
                <option value="320">320px</option>
                <option value="480">480px</option>
                <option value="640">640px</option>
                <option value="800">800px</option>
                <option value="1024">1024px</option>
              </select>
            </div>
          </div>
        </div>
      </div>

      <!-- 进度条 -->
      <div class="progress-container" id="progressContainer">
        <div class="progress-bar">
          <div class="progress-fill" id="progressFill"></div>
        </div>
        <div class="progress-text" id="progressText">准备中...</div>
      </div>

      <!-- 操作按钮 -->
      <div class="actions">
        <button class="btn-primary" id="convertBtn" disabled>
          🚀 开始转换
        </button>
      </div>

      <!-- 状态消息 -->
      <div class="status-message" id="statusMessage">
        📤 请上传视频文件开始转换
      </div>
      <div class="error-message" id="errorMessage"></div>

      <!-- 下载区域 -->
      <div class="download-section" id="downloadSection">
        <div class="webp-preview" id="webpPreview">
          <!-- WebP预览将在这里显示 -->
        </div>
        <div class="webp-info" id="webpInfo">
          <!-- WebP信息将在这里显示 -->
        </div>
        <div class="actions">
          <button class="btn-success" id="downloadBtn">
            📥 下载WebP动态图
          </button>
        </div>
      </div>

      <!-- 使用说明 -->
      <div class="instructions">
        <h3>📋 使用说明</h3>
        <ol>
          <li>上传您要转换的视频文件（支持MP4、AVI、MOV等格式）</li>
          <li>选择是否使用完整视频时长，或自定义开始和结束时间</li>
          <li>调整质量、帧率和宽度设置以获得最佳效果</li>
          <li>点击"开始转换"按钮，等待处理完成</li>
          <li>预览生成的WebP动态图并下载</li>
        </ol>
        <p>
          💡
          提示：WebP格式支持动画且文件大小较小，适合网页使用。建议使用中等质量和15FPS以获得最佳的文件大小与质量平衡。
        </p>
      </div>

      <footer>
        <p>🎨 视频转WebP动态图工具 - 让您的视频变成精美的动态图片</p>
      </footer>
    </div>

    <script>
      let ffmpeg = null
      let inputFile = null
      let currentVideo = null
      let webpBlob = null

      // DOM元素
      const fileUpload = document.getElementById('fileUpload')
      const videoInput = document.getElementById('videoInput')
      const videoPreview = document.getElementById('videoPreview')
      const useFullDuration = document.getElementById('useFullDuration')
      const timeSettings = document.getElementById('timeSettings')
      const timeControls = document.getElementById('timeControls')
      const startTimeInput = document.getElementById('startTime')
      const endTimeInput = document.getElementById('endTime')
      const currentTimeDisplay = document.getElementById('currentTimeDisplay')
      const qualitySelect = document.getElementById('quality')
      const fpsSelect = document.getElementById('fps')
      const customFpsGroup = document.getElementById('customFpsGroup')
      const customFpsInput = document.getElementById('customFps')
      const widthSelect = document.getElementById('width')
      const convertBtn = document.getElementById('convertBtn')
      const progressContainer = document.getElementById('progressContainer')
      const progressFill = document.getElementById('progressFill')
      const progressText = document.getElementById('progressText')
      const statusMessage = document.getElementById('statusMessage')
      const errorMessage = document.getElementById('errorMessage')
      const downloadSection = document.getElementById('downloadSection')
      const webpPreview = document.getElementById('webpPreview')
      const webpInfo = document.getElementById('webpInfo')
      const downloadBtn = document.getElementById('downloadBtn')

      // 初始化
      function init() {
        // 文件上传事件
        videoInput.addEventListener('change', handleFileSelect)

        // 拖拽上传
        fileUpload.addEventListener('dragover', handleDragOver)
        fileUpload.addEventListener('dragleave', handleDragLeave)
        fileUpload.addEventListener('drop', handleDrop)

        // 时长设置切换
        useFullDuration.addEventListener('change', toggleDurationSettings)

        // 帧率选择器
        fpsSelect.addEventListener('change', handleFpsChange)

        // 转换按钮
        convertBtn.addEventListener('click', convertToWebP)

        // 下载按钮
        downloadBtn.addEventListener('click', downloadWebP)
      }

      // 处理文件选择
      function handleFileSelect(event) {
        const file = event.target.files[0]
        if (file) {
          loadVideoFile(file)
        }
      }

      // 拖拽处理
      function handleDragOver(e) {
        e.preventDefault()
        fileUpload.classList.add('dragover')
      }

      function handleDragLeave(e) {
        e.preventDefault()
        fileUpload.classList.remove('dragover')
      }

      function handleDrop(e) {
        e.preventDefault()
        fileUpload.classList.remove('dragover')
        const files = e.dataTransfer.files
        if (files.length > 0) {
          loadVideoFile(files[0])
        }
      }

      // 加载视频文件
      function loadVideoFile(file) {
        if (!file.type.startsWith('video/')) {
          showError('❌ 请选择有效的视频文件')
          return
        }

        inputFile = file
        const videoUrl = URL.createObjectURL(file)

        videoPreview.style.display = 'block'
        videoPreview.innerHTML = `
          <video controls>
            <source src="${videoUrl}" type="${file.type}">
            您的浏览器不支持视频预览
          </video>
          <p style="text-align: center; padding: 15px 0; color: var(--text-secondary); font-weight: 500;">
            📁 ${file.name} (${formatFileSize(file.size)})
          </p>
        `

        // 获取视频元素引用
        currentVideo = videoPreview.querySelector('video')

        // 获取视频时长并设置默认结束时间
        currentVideo.addEventListener('loadedmetadata', () => {
          if (!endTimeInput.value || endTimeInput.value == 10) {
            endTimeInput.value = Math.floor(currentVideo.duration)
          }
          timeControls.style.display = useFullDuration.checked ? 'none' : 'flex'
        })

        // 监听时间更新
        currentVideo.addEventListener('timeupdate', updateCurrentTime)

        // 启用转换按钮
        convertBtn.disabled = false
        downloadSection.style.display = 'none'
        statusMessage.textContent = '✨ 请设置转换参数并开始处理'
        errorMessage.textContent = ''
      }

      // 切换时长设置
      function toggleDurationSettings() {
        const isFullDuration = useFullDuration.checked
        timeSettings.style.display = isFullDuration ? 'none' : 'flex'
        timeControls.style.display = isFullDuration ? 'none' : 'flex'
      }

      // 处理帧率选择变化
      function handleFpsChange() {
        const selectedFps = fpsSelect.value
        if (selectedFps === 'custom') {
          customFpsGroup.style.display = 'block'
        } else {
          customFpsGroup.style.display = 'none'
        }
      }

      // 更新当前时间显示
      function updateCurrentTime() {
        if (currentVideo) {
          const currentTime = currentVideo.currentTime
          const minutes = Math.floor(currentTime / 60)
          const seconds = Math.floor(currentTime % 60)
          currentTimeDisplay.textContent = `${minutes
            .toString()
            .padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
        }
      }

      // 获取当前时间
      function getCurrentTime(type) {
        if (!currentVideo) {
          showError('❌ 请先上传视频文件')
          return
        }

        const currentTime = Math.floor(currentVideo.currentTime * 10) / 10

        if (type === 'start') {
          startTimeInput.value = currentTime
          statusMessage.textContent = `⏰ 已设置开始时间: ${formatTime(
            currentTime
          )}`
        } else if (type === 'end') {
          endTimeInput.value = currentTime
          statusMessage.textContent = `⏰ 已设置结束时间: ${formatTime(
            currentTime
          )}`
        }
      }

      // 转换为WebP
      async function convertToWebP() {
        if (!inputFile) {
          showError('❌ 请先上传视频文件')
          return
        }

        try {
          statusMessage.textContent = '🚀 正在加载FFmpeg引擎...'
          statusMessage.classList.add('processing')
          errorMessage.textContent = ''
          convertBtn.disabled = true
          progressContainer.style.display = 'block'
          downloadSection.style.display = 'none'

          // 初始化FFmpeg
          if (!ffmpeg) {
            const { createFFmpeg, fetchFile } = FFmpeg
            ffmpeg = createFFmpeg({
              log: true,
            })

            // 监听进度
            ffmpeg.setProgress(({ ratio }) => {
              const percent = Math.floor(ratio * 100)
              progressFill.style.width = `${percent}%`
              progressText.textContent = `🎯 处理中: ${percent}%`
            })

            await ffmpeg.load()
          }

          const { fetchFile } = FFmpeg
          const quality = qualitySelect.value
          let fps = fpsSelect.value

          // 处理自定义帧率
          if (fps === 'custom') {
            const customFps = parseInt(customFpsInput.value)
            if (!customFps || customFps < 1 || customFps > 120) {
              showError('❌ 请输入有效的自定义帧率 (1-120)')
              return
            }
            fps = customFps.toString()
          }

          const width = widthSelect.value

          // 获取时间参数
          let startTime = 0
          let duration = null

          if (!useFullDuration.checked) {
            startTime = parseFloat(startTimeInput.value) || 0
            const endTime =
              parseFloat(endTimeInput.value) || currentVideo.duration
            duration = endTime - startTime

            if (duration <= 0) {
              showError('❌ 结束时间必须大于开始时间')
              return
            }
          }

          // 写入视频文件到虚拟文件系统
          const inputName = 'input.' + inputFile.name.split('.').pop()
          const outputName = 'output.webp'

          statusMessage.textContent = '📁 正在加载视频文件...'
          ffmpeg.FS('writeFile', inputName, await fetchFile(inputFile))

          // 构建FFmpeg命令
          const args = ['-i', inputName]

          // 添加开始时间
          if (startTime > 0) {
            args.push('-ss', startTime.toString())
          }

          // 添加持续时间
          if (duration !== null) {
            args.push('-t', duration.toString())
          }

          // 设置帧率
          args.push('-r', fps.toString())

          // 构建视频滤镜
          let vfilters = []

          // 设置宽度（高度自动计算保持比例）
          if (width !== '-1') {
            vfilters.push(`scale=${width}:-1`)
          }

          // 设置帧率滤镜
          vfilters.push(`fps=${fps}`)

          // 如果有滤镜，添加到命令中
          if (vfilters.length > 0) {
            args.push('-vf', vfilters.join(','))
          }

          // WebP动态图专用参数
          args.push('-c:v', 'libwebp') // 使用WebP编码器
          args.push('-lossless', '1') // 无损压缩
          args.push('-loop', '0') // 无限循环
          args.push('-preset', 'picture') // 图片预设，更适合高质量
          args.push('-compression_level', '6') // 压缩级别（0-6，6为最高质量）

          // 设置质量（无损模式下主要影响编码速度）
          const qualityMap = {
            high: '100',
            medium: '90',
            low: '80',
          }
          args.push('-quality', qualityMap[quality])

          // 输出文件
          args.push(outputName)

          statusMessage.textContent = '🎬 正在转换为WebP动态图...'

          // 执行转换
          await ffmpeg.run(...args)

          // 读取输出文件
          const data = ffmpeg.FS('readFile', outputName)
          webpBlob = new Blob([data.buffer], { type: 'image/webp' })

          // 显示结果
          showResult()

          statusMessage.textContent = '🎉 WebP动态图转换完成！'
          statusMessage.classList.remove('processing')
          progressText.textContent = '✅ 转换完成'
          progressFill.style.width = '100%'

          // 清理临时文件
          ffmpeg.FS('unlink', inputName)
          ffmpeg.FS('unlink', outputName)
        } catch (error) {
          console.error('转换失败:', error)
          showError(`❌ 转换失败: ${error.message}`)
          statusMessage.classList.remove('processing')
          convertBtn.disabled = false
        }
      }

      // 显示转换结果
      function showResult() {
        const webpUrl = URL.createObjectURL(webpBlob)

        // 显示预览
        webpPreview.innerHTML = `
          <img src="${webpUrl}" alt="WebP动态图预览" />
        `

        // 显示文件信息
        const originalSize = inputFile.size
        const webpSize = webpBlob.size
        const compressionRatio = (
          ((originalSize - webpSize) / originalSize) *
          100
        ).toFixed(1)

        webpInfo.innerHTML = `
          <div class="webp-info-item">
            <div class="webp-info-label">原始大小</div>
            <div class="webp-info-value">${formatFileSize(originalSize)}</div>
          </div>
          <div class="webp-info-item">
            <div class="webp-info-label">WebP大小</div>
            <div class="webp-info-value">${formatFileSize(webpSize)}</div>
          </div>
          <div class="webp-info-item">
            <div class="webp-info-label">压缩率</div>
            <div class="webp-info-value">${compressionRatio}%</div>
          </div>
        `

        downloadSection.style.display = 'flex'
      }

      // 下载WebP文件
      function downloadWebP() {
        if (!webpBlob) {
          showError('❌ 没有可下载的文件')
          return
        }

        // 创建新的Blob确保正确的MIME类型
        const downloadBlob = new Blob([webpBlob], {
          type: 'application/octet-stream',
        })

        const url = URL.createObjectURL(downloadBlob)
        const a = document.createElement('a')
        a.href = url
        a.download = inputFile.name.replace(/\.[^/.]+$/, '') + '.webp'
        a.setAttribute('download', a.download) // 强制下载
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)
        URL.revokeObjectURL(url)

        statusMessage.textContent = '📥 WebP动态图下载完成！'
      }

      // 显示错误信息
      function showError(message) {
        errorMessage.textContent = message
        statusMessage.classList.remove('processing')
        convertBtn.disabled = false
        progressContainer.style.display = 'none'
      }

      // 格式化文件大小
      function formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes'
        const k = 1024
        const sizes = ['Bytes', 'KB', 'MB', 'GB']
        const i = Math.floor(Math.log(bytes) / Math.log(k))
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
      }

      // 格式化时间
      function formatTime(seconds) {
        const minutes = Math.floor(seconds / 60)
        const secs = Math.floor(seconds % 60)
        return `${minutes}:${secs.toString().padStart(2, '0')}`
      }

      // 页面加载完成后初始化
      document.addEventListener('DOMContentLoaded', init)
    </script>
  </body>
</html>
